﻿Imports EDMDesigner.Business.CSDL
Imports EDMDesigner.Business.CSDL.Association
Imports EDMDesigner.Business.CSDL.Type
Imports EDMDesigner.Business.CSDL.Property.Navigation

Imports <xmlns="http://schemas.microsoft.com/ado/2006/04/edm">

Friend Module WriterCSDL
    Private visibilityNS As XNamespace = "http://schemas.microsoft.com/ado/2006/04/codegeneration"

    Friend Function WriteCSDL(ByVal csdl As CSDLContainer) As XElement
        Dim csdlNamespace = String.Concat(csdl.Namespace, ".")
        Dim csdlAlias = String.Concat(csdl.Alias, ".")
        Return <Schema Namespace=<%= csdl.Namespace %> Alias=<%= csdl.Alias %> xmlns="http://schemas.microsoft.com/ado/2006/04/edm">
                   <EntityContainer Name=<%= csdl.Name %>>
                       <%= From entitySet In csdl.EntitySets _
                           Select <EntitySet Name=<%= entitySet.EntitySetName %> EntityType=<%= String.Concat(csdlNamespace, entitySet.Name) %>/> _
                           .AddAttribute(visibilityNS, "GetterAccess", entitySet.EntitySetVisibility) %>
                       <%= From associationSet In csdl.Associations _
                           Select <AssociationSet Name=<%= associationSet.AssociationSetName %> Association=<%= String.Concat(csdlNamespace, associationSet.Name) %>>
                                      <End Role=<%= associationSet.PropertyEnd1Role %> EntitySet=<%= associationSet.PropertyEnd1.EntityType.EntitySetName %>/>
                                      <End Role=<%= associationSet.PropertyEnd2Role %> EntitySet=<%= associationSet.PropertyEnd2.EntityType.EntitySetName %>/>
                                  </AssociationSet> %>
                       <%= From funct In csdl.Functions _
                           Select <FunctionImport Name=<%= funct.Name %>>
                                      <%= From funcParameter In funct.Parameters _
                                          Select <Parameter Name=<%= funcParameter.Name %> Type=<%= funcParameter.Type %>/> _
                                          .AddAttribute("MaxLength", funcParameter.MaxLength) _
                                          .AddAttribute("Mode", funcParameter.Mode) _
                                          .AddAttribute("Precision", funcParameter.Precision) _
                                          .AddAttribute("Scale", funcParameter.Scale) %>
                                  </FunctionImport> _
                           .AddAttribute("EntitySet", If(funct.EntityType Is Nothing, Nothing, funct.EntityType.EntitySetName)) _
                           .AddAttribute("ReturnType", funct.ReturnType) %>
                   </EntityContainer>
                   <%= From complexType In csdl.ComplexTypes _
                       Select <ComplexType Name=<%= complexType.Name %>>
                                  <%= WriteScalarProperties(complexType) %>
                                  <%= WriteComplexProperties(complexType, csdlAlias) %>
                              </ComplexType> _
                       .AddAttribute(visibilityNS, "TypeAccess", complexType.Visibility) %>
                   <%= From entityType In csdl.EntityTypes _
                       Select <EntityType Name=<%= entityType.Name %>>
                                  <%= If(entityType.SpecificKeys.Any(), <Key>
                                                                            <%= From scalarProperty In entityType.ScalarProperties _
                                                                                Where scalarProperty.IsKey _
                                                                                Select <PropertyRef Name=<%= scalarProperty.Name %>/> %>
                                                                        </Key>, Nothing) %>
                                  <%= WriteScalarProperties(entityType) %>
                                  <%= WriteComplexProperties(entityType, csdlAlias) %>
                                  <%= From navigationProperty In entityType.NavigationProperties _
                                      Where navigationProperty.Generate _
                                      Select <NavigationProperty Name=<%= navigationProperty.Name %> Relationship=<%= String.Concat(csdlNamespace, navigationProperty.Association.Name) %> FromRole=<%= navigationProperty.Association.GetRoleName(navigationProperty) %> ToRole=<%= navigationProperty.Association.GetRoleName(navigationProperty.Association.PropertiesEnd.First(Function(role) role IsNot navigationProperty)) %>/> _
                                      .AddAttribute(visibilityNS, "GetterAccess", navigationProperty.GetVisibility) _
                                      .AddAttribute(visibilityNS, "SetterAccess", navigationProperty.SetVisibility) %>
                              </EntityType> _
                       .AddAttribute(visibilityNS, "TypeAccess", entityType.Visibility) _
                       .AddAttribute("BaseType", If(entityType.BaseType Is Nothing, Nothing, String.Concat(csdlNamespace, entityType.BaseType.Name))) _
                       .AddAttribute("Abstract", entityType.Abstract) %>
                   <%= From association In csdl.Associations _
                       Select <Association Name=<%= association.Name %>>
                                  <End Role=<%= association.PropertyEnd1Role %> Type=<%= String.Concat(csdlNamespace, association.PropertyEnd1.EntityType.Name) %> Multiplicity=<%= EDMDesigner.Business.AssociationBase.CardinalityStringConverter.CardinalityToSTring(association.PropertyEnd1.Cardinality) %>/>
                                  <End Role=<%= association.PropertyEnd2Role %> Type=<%= String.Concat(csdlNamespace, association.PropertyEnd2.EntityType.Name) %> Multiplicity=<%= EDMDesigner.Business.AssociationBase.CardinalityStringConverter.CardinalityToSTring(association.PropertyEnd2.Cardinality) %>/>
                              </Association> _
                       .AddElement(If(association.PrincipalRole Is Nothing, Nothing, <ReferentialConstraint>
                                                                                         <Principal Role=<%= association.PrincipalRole %>>
                                                                                             <%= From propertyRef In association.PrincipalProperties _
                                                                                                 Select <PropertyRef Name=<%= propertyRef.Name %>/> %>
                                                                                         </Principal>
                                                                                         <Dependent Role=<%= association.DependentRole %>>
                                                                                             <%= From propertyRef In association.DependentProperties _
                                                                                                 Select <PropertyRef Name=<%= propertyRef.Name %>/> %>
                                                                                         </Dependent>
                                                                                     </ReferentialConstraint>)) %>
               </Schema>
    End Function

    Private Function WriteScalarProperties(ByVal type As TypeBase) As IEnumerable(Of XElement)
        Return From scalarProperty In type.ScalarProperties _
                   Select <Property Name=<%= scalarProperty.Name %> Type=<%= scalarProperty.Type %>/> _
                   .AddAttribute("Collation", scalarProperty.Collation) _
                   .AddAttribute("ConcurrencyMode", scalarProperty.ConcurrencyMode) _
                   .AddAttribute("DefaultValue", scalarProperty.DefaultValue) _
                   .AddAttribute("FixedLength", scalarProperty.FixedLength) _
                   .AddAttribute(visibilityNS, "GetterAccess", scalarProperty.GetVisibility) _
                   .AddAttribute("MaxLength", scalarProperty.MaxLength) _
                   .AddAttribute("Nullable", scalarProperty.Nullable) _
                   .AddAttribute("Precision", scalarProperty.Precision) _
                   .AddAttribute("Scale", scalarProperty.Scale) _
                   .AddAttribute(visibilityNS, "SetterAccess", scalarProperty.SetVisibility) _
                   .AddAttribute("Unicode", scalarProperty.Unicode)
    End Function

    Private Function WriteComplexProperties(ByVal type As TypeBase, ByVal csdlAlias As String) As IEnumerable(Of XElement)
        Return From complexProperty In type.ComplexProperties _
                   Select <Property Name=<%= complexProperty.Name %> Type=<%= String.Concat(csdlAlias, complexProperty.ComplexType.Name) %> Nullable=<%= False %>/> _
                   .AddAttribute(visibilityNS, "GetterAccess", complexProperty.GetVisibility)
    End Function

End Module
